﻿//TODO: Test, Filter
//Gabor filter implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public class Filter : BaseImageFilter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Filter"/> class.
        /// </summary>
        public Filter()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Filter"/> class.
        /// </summary>
        /// <param name="_filter">The _filter.</param>
        internal Filter(Filter _filter)
        {
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;

            /*            int y = 0;
                        int x = 0;
                        for (y = 0; y < bitmap.Height - 1; y++)
                        {
                            for (x = 1; x < bitmap.Width - 1; x++)
                            {
                                double theta = 0.9f;
                                double rho = x * Math.Cos(theta) + y * Math.Sin(theta);
                                Color color = bitmap.GetPixel(x, y);
                                bitmap.SetPixel(x, y, Color.FromArgb(255, Color.FromArgb((int)(255 * rho * color.ToArgb()))));
                            }
                        }*/

            //% bw    = bandwidth, (1)
            //% gamma = aspect ratio, (0.5)
            //% psi   = phase shift, (0)
            //% lambda= wave length, (>=2)
            //% theta = angle in rad, [0 pi)

            double dSigma = 11.0f;
            double dGamma = 0.5f;
            double dTheta = Math.PI*180;
            double dLambda = 41.0f;
            double dPsi = 0;

            
            double nstds = 3;

            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;
            List<int> aSort = new List<int>();

            int y = 0;
            int x = 0;
            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    dGamma = bitmap.GetPixel(x, y).GetBrightness();
                    double sigma_x = dSigma;
                    double sigma_y = dSigma / dGamma;

                    //% Bounding box
                    double xmax = Math.Max(Math.Abs(nstds * sigma_x * Math.Cos(dTheta)), Math.Abs(nstds * sigma_y * Math.Sin(dTheta)));
                    xmax = Math.Ceiling(Math.Max(1, xmax));
                    double ymax = Math.Max(Math.Abs(nstds * sigma_x * Math.Sin(dTheta)), Math.Abs(nstds * sigma_y * Math.Cos(dTheta)));
                    ymax = Math.Ceiling(Math.Max(1, ymax));
                    double xmin = -xmax;
                    double ymin = -ymax;
                    //[x,y] = meshgrid(xmin:xmax,ymin:ymax);

                    //% Rotation 
                    double x_theta = x * Math.Cos(dTheta) + y * Math.Sin(dTheta);
                    double y_theta = -x * Math.Sin(dTheta) + y * Math.Cos(dTheta);

                    double gb = Math.Exp(-.5 * (Math.Pow(x_theta, 2) / Math.Pow(sigma_x, 2) + Math.Pow(y_theta, 2) / Math.Pow(sigma_y, 2))) * Math.Cos(2 * Math.PI / dLambda * x_theta + dPsi);

                    int nValue = (int)(gb * 255.0f);
                    if (nValue < 0)
                    {
                        nValue = 255 - nValue * -1;
                    }
                    bitmap.SetPixel(x, y, Color.FromArgb(nValue, nValue, nValue));
                    aSort.Add(nValue);
                }
            }

            aSort.Sort();
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Filter(this);
        }
    }
}
